#include <math.h>
#include "Math.h"
#include "Surface.h"

void Surface_DrawPixel(SDL_Surface *surface, int x, int y, Uint32 pixel)
{
    int bpp = surface->format->BytesPerPixel;
    /* Here p is the address to the pixel we want to set */
    Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;

    switch(bpp) {
    case 1:
        *p = pixel;
        break;

    case 2:
        *(Uint16 *)p = pixel;
        break;

    case 3:
        if(SDL_BYTEORDER == SDL_BIG_ENDIAN) {
            p[0] = (pixel >> 16) & 0xff;
            p[1] = (pixel >> 8) & 0xff;
            p[2] = pixel & 0xff;
        } else {
            p[0] = pixel & 0xff;
            p[1] = (pixel >> 8) & 0xff;
            p[2] = (pixel >> 16) & 0xff;
        }
        break;

    case 4:
        *(Uint32 *)p = pixel;
        break;
    }
}

Uint32 Surface_ReadPixel(SDL_Surface *surface, int x, int y)
{
    int bpp = surface->format->BytesPerPixel;
    /* Here p is the address to the pixel we want to retrieve */
    Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;

    switch(bpp) {
    case 1:
        return *p;
        break;

    case 2:
        return *(Uint16 *)p;
        break;

    case 3:
        if(SDL_BYTEORDER == SDL_BIG_ENDIAN)
            return p[0] << 16 | p[1] << 8 | p[2];
        else
            return p[0] | p[1] << 8 | p[2] << 16;
        break;

    case 4:
        return *(Uint32 *)p;
        break;

    default:
        return 0;       /* shouldn't happen, but avoids warnings */
    }
}

SDL_Surface *Surface_ScaleSurfaceFast(SDL_Surface *Surface, Uint16 Width, Uint16 Height)
{   
    SDL_Surface *Return = SDL_CreateRGBSurface(Surface->flags, Width, Height, Surface->format->BitsPerPixel,
        Surface->format->Rmask, Surface->format->Gmask, Surface->format->Bmask, Surface->format->Amask);

	int X, Y;
	float OldX, OldY, XInc=Surface->w/Width, YInc=Surface->h/Height;
	
	OldY=0;
	for(Y=0;Y<Height;++Y)
	{
		OldX=0;
		for(X=0;X<Width;++X)
		{
			Surface_DrawPixel(Return, (Sint32)X, (Sint32)Y, Surface_ReadPixel(Surface, (Sint32)OldX, (Sint32)OldY));
			OldX+=XInc;
		}
		OldY+=YInc;
	}

    return Return;
}

SDL_Surface *Surface_RotateSurface(SDL_Surface *Surface, float RotationAngle, int Crop)
{
	SDL_Surface *_ret = SDL_CreateRGBSurface(Surface->flags, Surface->w, Surface->h, Surface->format->BitsPerPixel,
        Surface->format->Rmask, Surface->format->Gmask, Surface->format->Bmask, Surface->format->Amask);

	int X, Y, CentreX=Surface->w/2, CentreY=Surface->h/2, OldX, OldY;
	float DistanceToCentre, AngleFromCentre, NewAngle;
	for(Y=0;Y<Surface->h;++Y)
	{
		for(X=0;X<Surface->w;++X)
		{
			DistanceToCentre=sqrt((X-CentreX)*(X-CentreX)+(Y-CentreY)*(Y-CentreY));
			
			if (!Crop || DistanceToCentre<Surface->w/2 || DistanceToCentre<Surface->h/2)
			{
				AngleFromCentre=Math_XYAngle(CentreX, CentreY, X, Y);
				NewAngle=Math_NormaliseAngle(AngleFromCentre-RotationAngle);
				
				OldX=((int)(CentreX+Math_AngleX(NewAngle)*DistanceToCentre));
				OldY=((int)(CentreY+Math_AngleY(NewAngle)*DistanceToCentre));
				
				if (OldX>=0 && OldX<Surface->w && OldY>=0 && OldY<Surface->h)
					Surface_DrawPixel(_ret, X, Y, Surface_ReadPixel(Surface, OldX, OldY));
			}
		}
	}
	
	return _ret;
}